home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP06.ZIP / CHAP06 / POLYLINE / POLYLINE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-22  |  13.0 KB  |  580 lines

  1. /*
  2.  * POLYLINE.CPP
  3.  * Polyline Component Object Chapter 6
  4.  *
  5.  * Implementation of the CPolyline class that we expose as an
  6.  * OLE 2.0 component object.
  7.  *
  8.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Software Design Engineer
  11.  * Microsoft Systems Developer Relations
  12.  *
  13.  * Internet  :  kraigb@microsoft.com
  14.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  15.  */
  16.  
  17.  
  18. #include "polyline.h"
  19.  
  20.  
  21. /*
  22.  * CPolyline:CPolyline
  23.  * CPolyline::~CPolyline
  24.  *
  25.  * Constructor Parameters:
  26.  *  punkOuter       LPUNKNOWN of the controlling unknown.
  27.  *  pfnDestroy      LPFNDESTROYED to call when an object is destroyed.
  28.  *  hInst           HINSTANCE of the application we're in.
  29.  */
  30.  
  31. CPolyline::CPolyline(LPUNKNOWN punkOuter, LPFNDESTROYED pfnDestroy
  32.     , HINSTANCE hInst)
  33.     {
  34.     m_hWnd=NULL;
  35.     m_hInst=hInst;
  36.  
  37.     m_cRef=0;
  38.     m_punkOuter=punkOuter;
  39.     m_pfnDestroy=pfnDestroy;
  40.     m_fDirty=FALSE;
  41.  
  42.     m_pST=NULL;
  43.     m_cf =0;
  44.  
  45.     //CHAPTER6MOD
  46.     m_clsID=CLSID_Polyline6;
  47.     m_iID  =IID_IPolyline6;
  48.  
  49.     //NULL any contained interfaces initially.
  50.     m_pIPolyline        =NULL;
  51.     m_pIPersistStorage  =NULL;
  52.     m_pIDataObject      =NULL;
  53.     m_pIDataAdviseHolder=NULL;
  54.     m_pAdv              =NULL;
  55.  
  56.     //Initialize IDataObject::EnumFormatEtc arrays
  57.     m_cf=RegisterClipboardFormat(SZPOLYLINECLIPFORMAT);
  58.  
  59.     m_cfeGet=CFORMATETCGET;
  60.     m_cfeSet=CFORMATETCSET;
  61.  
  62.     SETDefFormatEtc(m_rgfeGet[0], m_cf, TYMED_HGLOBAL);
  63.     SETDefFormatEtc(m_rgfeGet[1], CF_METAFILEPICT, TYMED_MFPICT);
  64.     SETDefFormatEtc(m_rgfeGet[2], CF_BITMAP, TYMED_GDI);
  65.  
  66.     SETDefFormatEtc(m_rgfeSet[0], m_cf, TYMED_HGLOBAL);
  67.     //End CHAPTER6MOD
  68.     return;
  69.     }
  70.  
  71.  
  72. CPolyline::~CPolyline(void)
  73.     {
  74.     if (NULL!=m_pST)
  75.         delete m_pST;
  76.  
  77.     //Free our contained interfaces, delete those we own, Release others.
  78.     //CHAPTER6MOD
  79.     if (NULL!=m_pIDataAdviseHolder)
  80.         m_pIDataAdviseHolder->Release();
  81.  
  82.     if (NULL!=m_pIDataObject)
  83.         delete m_pIDataObject;
  84.     //End CHAPTER6MOD
  85.  
  86.     if (NULL!=m_pIPersistStorage)
  87.         delete m_pIPersistStorage;
  88.  
  89.     if (NULL!=m_pIPolyline)
  90.         delete m_pIPolyline;
  91.  
  92.     //Reverses the AddRef in ::SetAdvise
  93.     if (NULL!=m_pAdv)
  94.         m_pAdv->Release();
  95.  
  96.     return;
  97.     }
  98.  
  99.  
  100.  
  101.  
  102. /*
  103.  * CPolyline::FInit
  104.  *
  105.  * Purpose:
  106.  *  Performs any intiailization of a CPolyline that's prone to failure
  107.  *  that we also use internally before exposing the object outside
  108.  *  this DLL.
  109.  *
  110.  * Parameters:
  111.  *  None
  112.  *
  113.  * Return Value:
  114.  *  BOOL            TRUE if the function is successful, FALSE otherwise.
  115.  */
  116.  
  117. BOOL CPolyline::FInit(void)
  118.     {
  119.     LPUNKNOWN       pIUnknown=(LPUNKNOWN)this;
  120.  
  121.     if (NULL!=m_punkOuter)
  122.         pIUnknown=m_punkOuter;
  123.  
  124.     m_pST=new CStringTable(m_hInst);
  125.  
  126.     if (!m_pST->FInit(IDS_POLYLINEMIN, IDS_POLYLINEMAX))
  127.         return FALSE;
  128.  
  129.     //Allocate contained interfaces.
  130.     m_pIPolyline=new CImpIPolyline(this, pIUnknown);
  131.  
  132.     if (NULL==m_pIPolyline)
  133.         return FALSE;
  134.  
  135.     m_pIPersistStorage=new CImpIPersistStorage(this, pIUnknown);
  136.  
  137.     if (NULL==m_pIPersistStorage)
  138.         return FALSE;
  139.  
  140.     //CHAPTER6MOD
  141.     m_pIDataObject=new CImpIDataObject(this, pIUnknown);
  142.  
  143.     if (NULL==m_pIDataObject)
  144.         return FALSE;
  145.     //End CHAPTER6MOD
  146.  
  147.     return TRUE;
  148.     }
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156. /*
  157.  * CPolyline::QueryInterface
  158.  * CPolyline::AddRef
  159.  * CPolyline::Release
  160.  *
  161.  * Purpose:
  162.  *  IUnknown members for CPolyline object.
  163.  */
  164.  
  165. STDMETHODIMP CPolyline::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  166.     {
  167.     *ppv=NULL;
  168.  
  169.     /*
  170.      * The only calls we get here for IUnknown are either in a non-aggregated
  171.      * case or when we're created in an aggregation, so in either we always
  172.      * return our IUnknown for IID_IUnknown.
  173.      */
  174.     if (IsEqualIID(riid, IID_IUnknown))
  175.         *ppv=(LPVOID)this;
  176.  
  177.     //For anything else we return contained interfaces.
  178.     if (IsEqualIID(riid, m_iID))
  179.         *ppv=(LPVOID)m_pIPolyline;
  180.  
  181.     if (IsEqualIID(riid, IID_IPersist) || IsEqualIID(riid, IID_IPersistStorage))
  182.         *ppv=(LPVOID)m_pIPersistStorage;
  183.  
  184.     //CHAPTER6MOD
  185.     if (IsEqualIID(riid, IID_IDataObject))
  186.         *ppv=(LPVOID)m_pIDataObject;
  187.     //End CHAPTER6MOD
  188.  
  189.     //AddRef any interface we'll return.
  190.     if (NULL!=*ppv)
  191.         {
  192.         ((LPUNKNOWN)*ppv)->AddRef();
  193.         return NOERROR;
  194.         }
  195.  
  196.     return ResultFromScode(E_NOINTERFACE);
  197.     }
  198.  
  199.  
  200. STDMETHODIMP_(ULONG) CPolyline::AddRef(void)
  201.     {
  202.     return ++m_cRef;
  203.     }
  204.  
  205.  
  206. STDMETHODIMP_(ULONG) CPolyline::Release(void)
  207.     {
  208.     ULONG       cRefT;
  209.  
  210.     cRefT=--m_cRef;
  211.  
  212.     if (0==m_cRef)
  213.         delete this;
  214.  
  215.     return cRefT;
  216.     }
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224. /*
  225.  * CPolyline::RectConvertMappings
  226.  *
  227.  * Purpose:
  228.  *  Converts the contents of a rectangle from device (MM_TEXT) or
  229.  *  HIMETRIC to the other.
  230.  *
  231.  * Parameters:
  232.  *  pRect           LPRECT containing the rectangle to convert.
  233.  *  fToDevice       BOOL TRUE to convert from HIMETRIC to device,
  234.  *                  FALSE to convert device to HIMETRIC.
  235.  *
  236.  * Return Value:
  237.  *  None
  238.  */
  239.  
  240. void CPolyline::RectConvertMappings(LPRECT pRect, BOOL fToDevice)
  241.     {
  242.     HDC      hDC;
  243.     int      iLpx, iLpy;
  244.  
  245.     if (NULL==pRect)
  246.         return;
  247.  
  248.     hDC=GetDC(NULL);
  249.     iLpx=GetDeviceCaps(hDC, LOGPIXELSX);
  250.     iLpy=GetDeviceCaps(hDC, LOGPIXELSY);
  251.     ReleaseDC(NULL, hDC);
  252.  
  253.     if (fToDevice)
  254.         {
  255.         pRect->left=MulDiv(iLpx, pRect->left, HIMETRIC_PER_INCH);
  256.         pRect->top =MulDiv(iLpy, pRect->top , HIMETRIC_PER_INCH);
  257.  
  258.         pRect->right =MulDiv(iLpx, pRect->right,  HIMETRIC_PER_INCH);
  259.         pRect->bottom=MulDiv(iLpy, pRect->bottom, HIMETRIC_PER_INCH);
  260.  
  261.        #ifdef NEVER
  262.         /*
  263.          * In this conversion we may get situations where the top
  264.          * coordinate is larger than the bottom, which messes us up.
  265.          */
  266.         if (pRect->bottom < pRect->top)
  267.             {
  268.             iLpy=pRect->top;
  269.             pRect->top=pRect->bottom;
  270.             pRect->bottom=iLpy;
  271.             }
  272.        #endif
  273.         }
  274.     else
  275.         {
  276.         pRect->left=MulDiv(pRect->left, HIMETRIC_PER_INCH, iLpx);
  277.         pRect->top =MulDiv(pRect->top , HIMETRIC_PER_INCH, iLpy);
  278.  
  279.         pRect->right =MulDiv(pRect->right,  HIMETRIC_PER_INCH, iLpx);
  280.         pRect->bottom=MulDiv(pRect->bottom, HIMETRIC_PER_INCH, iLpy);
  281.         }
  282.  
  283.     return;
  284.     }
  285.  
  286.  
  287.  
  288.  
  289. //CHAPTER6MOD
  290. //Functions now internal due to IDataObject
  291.  
  292. /*
  293.  * CPolyline::DataSet
  294.  *
  295.  * Purpose:
  296.  *  Sets the current data in this Polyline to a given structure.
  297.  *
  298.  * Parameters:
  299.  *  pplIn           LPPOLYLINEDATA to initialize to.
  300.  *  fSizeToData     BOOL indicating if we're to size to the data or scale it.
  301.  *  fNotify         BOOL indicating if we're to send an advise on this change.
  302.  *
  303.  * Return Value:
  304.  *  HRESULT         NOERROR if successful, otherwise a POLYLINE_E_ value.
  305.  */
  306.  
  307. STDMETHODIMP CPolyline::DataSet(LPPOLYLINEDATA pplIn, BOOL fSizeToData
  308.     , BOOL fNotify)
  309.     {
  310.     RECT            rc;
  311.  
  312.     /*
  313.      * Copy the structure in pplIn and repaint to reflect the new point
  314.      * set.  Note that unlike the RectSet message, we do no scaling,
  315.      * assuming that the rect in the structure is appropriate for the data.
  316.      */
  317.  
  318.     if (NULL==pplIn)
  319.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  320.  
  321.     //Preserve the old rectangle, then copy
  322.     rc=m_pl.rc;
  323.     m_pl=*pplIn;
  324.     m_fDirty=TRUE;
  325.  
  326.  
  327.     //CHAPTER6MOD
  328.     //Inform our parent of the data change
  329.     if (NULL!=m_pIDataAdviseHolder)
  330.         {
  331.         m_pIDataAdviseHolder->SendOnDataChange(m_pIDataObject
  332.             , DVASPECT_CONTENT, ADVF_NODATA);
  333.         }
  334.     //End CHAPTER6MOD
  335.  
  336.     /*
  337.      * If we're scaling the window to fit the data, then use
  338.      * RectSet passing our current rectangle as the new one.
  339.      * That makes sure that the data won't change but that the
  340.      * window is resized.
  341.      */
  342.  
  343.     if (fSizeToData)
  344.         {
  345.         POINT       pt;
  346.  
  347.         /*
  348.          * Get our offset in the parent window so we can RectSet
  349.          * to the right place since RectSet expects rectangle in
  350.          * parent coordinates and we get it in client coordinates.
  351.          */
  352.         GetWindowRect(m_hWnd, &rc);
  353.         pt.x=rc.left;
  354.         pt.y=rc.top;
  355.         ScreenToClient(GetParent(m_hWnd), &pt);
  356.         rc=m_pl.rc;
  357.         OffsetRect(&rc, pt.x, pt.y);
  358.  
  359.         //This will also cause a repaint.
  360.         m_pIPolyline->RectSet(&rc, fNotify);
  361.         }
  362.     else
  363.         {
  364.         //Make sure we're updated.
  365.         InvalidateRect(m_hWnd, NULL, TRUE);
  366.         UpdateWindow(m_hWnd);
  367.         }
  368.  
  369.     return NOERROR;
  370.     }
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378. /*
  379.  * CImpIPolyline::DataGet
  380.  *
  381.  * Purpose:
  382.  *  Retrieves the Polyline's current data.
  383.  *
  384.  * Parameters:
  385.  *  pplIn           LPPOLYLINEDATA into which we copy the data.
  386.  *
  387.  * Return Value:
  388.  *  HRESULT         NOERROR if successful, otherwise a POLYLINE_E_ value.
  389.  */
  390.  
  391. STDMETHODIMP CPolyline::DataGet(LPPOLYLINEDATA pplIn)
  392.     {
  393.     if (NULL==pplIn)
  394.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  395.  
  396.     *pplIn=m_pl;
  397.     return NOERROR;
  398.     }
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405. /*
  406.  * CPolyline::RenderNative
  407.  *
  408.  * Purpose:
  409.  *  Retrieves the Polyline's data in a global memory handle.
  410.  *
  411.  * Parameters:
  412.  *  phMem           HGLOBAL FAR * in which to store the handle.
  413.  *
  414.  * Return Value:
  415.  *  HRESULT         NOERROR if successful, otherwise a POLYLINE_E_ value.
  416.  */
  417.  
  418. STDMETHODIMP CPolyline::RenderNative(HGLOBAL FAR *phMem)
  419.     {
  420.     HGLOBAL         hMem;
  421.     LPPOLYLINEDATA  ppl;
  422.     HRESULT         hr=ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  423.  
  424.     if (NULL==phMem)
  425.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  426.  
  427.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, CBPOLYLINEDATA);
  428.  
  429.     if (NULL!=hMem)
  430.         {
  431.         ppl=(LPPOLYLINEDATA)GlobalLock(hMem);
  432.         hr=DataGet(ppl);
  433.  
  434.         GlobalUnlock(hMem);
  435.  
  436.         if (FAILED(hr))
  437.             {
  438.             GlobalFree(hMem);
  439.             hMem=NULL;
  440.             }
  441.         }
  442.  
  443.     *phMem=hMem;
  444.     return hr;
  445.     }
  446.  
  447.  
  448.  
  449.  
  450. /*
  451.  * CPolyline::RenderBitmap
  452.  *
  453.  * Purpose:
  454.  *  Creates a bitmap image of the current Polyline.
  455.  *
  456.  * Parameters:
  457.  *  phBmp           HBITMAP FAR * in which to return the bitmap.
  458.  *
  459.  * Return Value:
  460.  *  HRESULT         NOERROR if successful, otherwise a POLYLINE_E_ value.
  461.  */
  462.  
  463. STDMETHODIMP CPolyline::RenderBitmap(HBITMAP FAR *phBmp)
  464.     {
  465.     HDC             hDC;
  466.     HDC             hMemDC;
  467.     HBITMAP         hBmp;
  468.     RECT            rc;
  469.     HGDIOBJ         hObj;
  470.  
  471.     if (NULL==phBmp)
  472.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  473.  
  474.     //Render a bitmap the size of the current rectangle.
  475.     hDC=GetDC(m_hWnd);
  476.     hMemDC=CreateCompatibleDC(hDC);
  477.  
  478.     GetClientRect(m_hWnd, &rc);
  479.     hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  480.  
  481.     if (NULL!=hBmp)
  482.         {
  483.         //Draw the POLYLINEDATA into the bitmap.
  484.         hObj=SelectObject(hMemDC, hBmp);
  485.         Draw(hMemDC, FALSE, TRUE);
  486.         SelectObject(hMemDC, hObj);
  487.         }
  488.  
  489.     DeleteDC(hMemDC);
  490.     ReleaseDC(m_hWnd, hDC);
  491.  
  492.     *phBmp=hBmp;
  493.     return NOERROR;
  494.     }
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502. /*
  503.  * CPolyline::RenderMetafilePict
  504.  *
  505.  * Purpose:
  506.  *  Renders the current Polyline into a METAFILEPICT structure in
  507.  *  global memory.
  508.  *
  509.  * Parameters:
  510.  *  phMem           HGLOBAL FAR * in which to return the METAFILEPICT.
  511.  *
  512.  * Return Value:
  513.  *  HRESULT         NOERROR if successful, otherwise a POLYLINE_E_ value.
  514.  */
  515.  
  516. STDMETHODIMP CPolyline::RenderMetafilePict(HGLOBAL FAR * phMem)
  517.     {
  518.     HGLOBAL         hMem;
  519.     HMETAFILE       hMF;
  520.     HDC             hDC;
  521.     LPMETAFILEPICT  pMF;
  522.     RECT            rc;
  523.  
  524.     if (NULL==phMem)
  525.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  526.  
  527.     hMF=NULL;
  528.  
  529.     //Create a memory metafile and return its handle.
  530.     hDC=(HDC)CreateMetaFile(NULL);
  531.  
  532.     if (NULL==hDC)
  533.         return ResultFromScode(STG_E_MEDIUMFULL);
  534.  
  535.     SetMapMode(hDC, MM_ANISOTROPIC);
  536.     GetClientRect(m_hWnd, &rc);
  537.     SetWindowOrg(hDC, 0, 0);
  538.     SetWindowExt(hDC, rc.right, rc.bottom);
  539.  
  540.     Draw(hDC, TRUE, TRUE);
  541.     hMF=CloseMetaFile(hDC);
  542.  
  543.     if (NULL==hMF)
  544.         return ResultFromScode(STG_E_MEDIUMFULL);
  545.  
  546.     //Allocate the METAFILEPICT structure.
  547.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
  548.  
  549.     if (NULL==hMem)
  550.         {
  551.         DeleteMetaFile(hMF);
  552.         return ResultFromScode(E_FAIL);
  553.         }
  554.  
  555.     /*
  556.      * Global lock only fails in PMODE if the selector is invalid
  557.      * (like it was discarded) or references a 0 length segment,
  558.      * neither of which can happen here.
  559.      */
  560.     pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  561.  
  562.     pMF->hMF=hMF;
  563.     pMF->mm=MM_ANISOTROPIC;
  564.  
  565.     //Insert the extents in MM_HIMETRIC units.
  566.     GetClientRect(m_hWnd, &rc);
  567.     RectConvertMappings(&rc, FALSE);
  568.     pMF->xExt=rc.right;
  569.     pMF->yExt=rc.bottom;
  570.  
  571.     GlobalUnlock(hMem);
  572.  
  573.     *phMem=hMem;
  574.     return NOERROR;
  575.     }
  576.  
  577.  
  578.  
  579. //End CHAPTER6MOD
  580.